package com.soa.zuul.filter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.util.StreamUtils;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulHeaders;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.util.HTTPRequestUtils;
import com.soa.zuul.entity.GatewayService;
import com.soa.zuul.service.FeignLogService;
import com.soa.zuul.util.CodeMsg;
import com.soa.zuul.util.Constant;
import com.soa.zuul.util.Json;
import com.soa.zuul.util.RequestUtil;
import com.soa.zuul.util.ZipStreamUtil;

/**
 * 拦截路由内容，日志并持久化。.
 * @author zheng
 *
 */
public class AccessSuccessFilter extends ZuulFilter {
	FeignLogService feignLogService;
	public AccessSuccessFilter (FeignLogService feignLogService){
		this.feignLogService=feignLogService;
	}
	public final static Logger logger = LoggerFactory.getLogger(AccessSuccessFilter.class);
	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest request = ctx.getRequest();
		CodeMsg codeMsg = CodeMsg.SUCCESS;
		String body =null;
		//通过URL从redis里查询服务对象
		GatewayService gatewayService = (GatewayService)ctx.get("gatewayService");
		// 不记录日志的话直接对该请求进行路由
		if(gatewayService!=null && (Constant.IsNeedLogNo.equals(gatewayService.getIsNeedLog()) ||  Constant.resultTypeNoString.equals(gatewayService.getResultType())) ){
			ctx.setSendZuulResponse(true); 
			//调用写日志服务
		}else{
			//判断是否是gzip格式
			boolean isGzipRequested = false;
			String requestedGzip =request.getHeader(ZuulHeaders.ACCEPT_ENCODING);
			if ((requestedGzip != null&& HTTPRequestUtils.getInstance().isGzipped(requestedGzip)) || ctx.getResponseGZipped()) {
	            isGzipRequested = true;
			}
			//获取字符集
			String ENCODING =  ZipStreamUtil.getEncoding(ctx.getZuulResponseHeaders());
			try {
				//如果配置为“原始格式”
				 if(gatewayService==null  || (gatewayService!=null && Constant.resultTypeFirsthand.equals(gatewayService.getResultType()))){
					 	//获取路由内容
						InputStream stream = ctx.getResponseDataStream();
						if(stream!=null){
							ByteArrayOutputStream byteArrayOutputStream= ZipStreamUtil.getByteArrayOutputStream(stream);
							InputStream sourceInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
							ctx.setResponseDataStream(sourceInputStream);
							InputStream storeInputStream =null;
							if (isGzipRequested) {
								try{
									storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
									body= ZipStreamUtil.getStringFromGZIPInputStream(storeInputStream, ENCODING);
								}catch(Exception e){
									storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
									body = StreamUtils.copyToString(storeInputStream, Charset.forName(ENCODING));
								}
							}else{
								storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
								body = StreamUtils.copyToString(storeInputStream, Charset.forName(ENCODING));
							}
						}
				}
				//如果配置为“返回标准json格式”
				 else if(gatewayService!=null && Constant.resultTypeJson.equals(gatewayService.getResultType())){ //标准josn格式，包装返回值
				 	//获取路由内容
					 	InputStream stream = ctx.getResponseDataStream();
					 	ByteArrayOutputStream byteArrayOutputStream= ZipStreamUtil.getByteArrayOutputStream(stream);
						InputStream storeInputStream =null;
					if (isGzipRequested) {  //gzip解压
						try{
							storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
							body= ZipStreamUtil.getStringFromGZIPInputStream(storeInputStream, ENCODING);
						}catch(Exception e){
							storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
							body = StreamUtils.copyToString(storeInputStream, Charset.forName(ENCODING));
						}
					}else{
						storeInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
						body = StreamUtils.copyToString(storeInputStream, Charset.forName(ENCODING)); //普通解压
					}
					if(Json.isGoodJson(body)){ //判断是否是JSON格式
						Object res = Json.GSON.fromJson(body, Object.class);
						codeMsg.setResponse(res);
					}else{
						codeMsg.setResponse(body);
					}
					//重新设置路由内容
//					System.out.println(Json.GSON2.toJson(codeMsg));
					ctx.setResponseBody(Json.GSON2.toJson(codeMsg));
				}
				else{  //如果配置为“其他数据格式”
					ctx.setSendZuulResponse(true); 
				}
				//调用写日志服务
//				feignLogService.writeLog(Json.GSON.toJson(RequestUtil.SendZuulResponseSucess(body, ctx)));
				return null;
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		return null;
	}

	/**
	 * 返回一个boolean类型来判断该过滤器是否要执行，返回true，则过滤器生效
	 * 
	 * @return
	 */
	@Override
	public boolean shouldFilter() {
		 RequestContext ctx = RequestContext.getCurrentContext();
		 if(ctx.get("isSuccess")==null) return false;
		 return (boolean) ctx.get("isSuccess");//
	}

	@Override
	public int filterOrder() {
		return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 3;//
	}

	/**
	 * 返回一个字符串代表过滤器的类型，在zuul中定义了四种不同生命周期的过滤器类型，具体如下： pre：可以在请求被路由之前调用
	 * routing：在路由请求时候被调用 post：在routing和error过滤器之后被调用 error：处理请求时发生错误时被调用
	 * 
	 * @return
	 */
	@Override
	public String filterType() {
		return FilterConstants.POST_TYPE;// 在请求被处理之后，会进入该过滤器
	}

}
